package resource

import (
	"database/sql"
	"fmt"
	"time"
)

import (
	_ "github.com/denisenkom/go-mssqldb"
)

import (
	dbc "dbConnector"
	"r_log"
	"util"
)

type Holidays map[util.DateAndTime]bool

//获取date之后的下一个交易日
func (res *Resource) GetNextMarketDay(date util.DateAndTime) (util.DateAndTime, error) {
	d, err := time.ParseInLocation("20060102", fmt.Sprintf("%v", date), time.Local)
	if err != nil {
		return date, fmt.Errorf("ParseInLocation(): %v", err)
	}

	res.HolidayLock.RLock()
	defer res.HolidayLock.RUnlock()
	for {
		d = d.AddDate(0, 0, 1)
		nextDay := util.DateAndTime(d.Year()*10000 + int(d.Month())*100 + d.Day())
		if int(d.Weekday()) > 0 && int(d.Weekday()) < 6 {
			if !res.HolidayList.isHoliday(nextDay) { //不在节假日表中
				return nextDay, nil
			}
		}
	}
}

//获取date之前（含date）最近的一个交易日
func (res *Resource) GetLastMarketDay(date util.DateAndTime) (util.DateAndTime, error) {
	d, err := time.ParseInLocation("20060102", fmt.Sprintf("%v", date), time.Local)
	if err != nil {
		return date, fmt.Errorf("ParseInLocation(): %v", err)
	}

	res.HolidayLock.RLock()
	defer res.HolidayLock.RUnlock()
	for {
		lastDay := util.DateAndTime(d.Year()*10000 + int(d.Month())*100 + d.Day())
		if int(d.Weekday()) > 0 && int(d.Weekday()) < 6 {
			if !res.HolidayList.isHoliday(lastDay) { //不在节假日表中
				return lastDay, nil
			}
		}
		d = d.AddDate(0, 0, -1)
	}
}

//获取date之后的节日信息表
func getHolidaysFromDB(db *sql.DB) (*Holidays, error) {
	rows, err := db.Query("SELECT * FROM _Stk_Date_Holiday")
	if err != nil {
		return nil, fmt.Errorf("db.Query(): %v", err)
	}
	defer rows.Close()
	holidays := make(Holidays)
	for rows.Next() {
		var date util.DateAndTime
		if err = rows.Scan(&date); err != nil {
			return nil, fmt.Errorf("rows.Scan(): %v", err)
		}
		holidays[date] = true
	}
	if err = rows.Err(); err != nil {
		return nil, fmt.Errorf("rows.Err(): %v", err)
	}
	return &holidays, nil
}

//判断date是否在节日表中
func (h *Holidays) isHoliday(date util.DateAndTime) bool {
	_, ok := (*h)[date]
	return ok
}

//判断下一个自然日是否是节假日
func (res *Resource) NextDayIsHoliday(date util.DateAndTime) (bool, error) {
	d, err := time.ParseInLocation("20060102", fmt.Sprintf("%v", date), time.Local)
	if err != nil {
		r_log.Logger.Error("NextDayIsHoliday : ParseInLocation(): %v", err)
		return false, fmt.Errorf("ParseInLocation(): %v", err)
	}

	d = d.AddDate(0, 0, 1)
	nextDay := util.DateAndTime(d.Year()*10000 + int(d.Month())*100 + d.Day())
	if int(d.Weekday()) > 0 && int(d.Weekday()) < 6 {
		res.HolidayLock.RLock()
		defer res.HolidayLock.RUnlock()
		if !res.HolidayList.isHoliday(nextDay) { //不在节假日表中
			return false, nil
		}
	}
	return true, nil
}

//判断今天是否是节假日
func (res *Resource) TodayIsHoliday() (bool, error) {
	today := util.Today()
	d, err := time.ParseInLocation("20060102", fmt.Sprintf("%v", today), time.Local)
	if err != nil {
		r_log.Logger.Error("TodayIsHoliday : ParseInLocation(): %v", err)
		return false, fmt.Errorf("ParseInLocation(): %v", err)
	}

	if int(d.Weekday()) > 0 && int(d.Weekday()) < 6 {
		res.HolidayLock.RLock()
		defer res.HolidayLock.RUnlock()
		if !res.HolidayList.isHoliday(today) { //不在节假日表中
			return false, nil
		}
	}
	return true, nil
}

//更新节日表
func (res *Resource) updateHolidayList() error {
	dbc.ServerLock.RLock()
	db := dbc.Servers.Holiday.DB
	dbc.ServerLock.RUnlock()

	/*	db, err := s.InitSqlServer()
		if err != nil {
			res.StateLock.Lock()
			res.State.HlState = util.STATE_ERROR
			res.StateLock.Unlock()
			return fmt.Errorf("initSqlServer(%v): %v", s, err)
		}
		defer db.Close()*/

	holidayList, err := getHolidaysFromDB(db)
	if err != nil {
		res.StateLock.Lock()
		res.State.HlState = util.STATE_ERROR
		res.StateLock.Unlock()
		return fmt.Errorf("getHolidaysFromDB(): %v", err)
	}
	res.HolidayLock.Lock()
	res.HolidayList = holidayList
	res.HolidayLock.Unlock()

	res.StateLock.Lock()
	res.State.HlState = util.STATE_READY
	res.StateLock.Unlock()
	return nil
}
